home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / rzsz9107.zip / RZ.C < prev    next >
C/C++ Source or Header  |  1991-05-31  |  30KB  |  1,444 lines

  1. #define VERSION "3.07 05-30-91"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*
  5.  *
  6.  * rz.c By Chuck Forsberg
  7.  *
  8.  * A program for Unix to receive files and commands from computers running
  9.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  10.  *  rz uses Unix buffered input to reduce wasted CPU time.
  11.  *
  12.  *
  13.  *    This version implements numerous enhancements including ZMODEM
  14.  *    Run Length Encoding and variable length headers.  These
  15.  *    features were not funded by the original Telenet development
  16.  *    contract.
  17.  * 
  18.  * This software may be freely used for non commercial and
  19.  * educational (didactic only) purposes.  This software may also
  20.  * be freely used to support file transfer operations to or from
  21.  * licensed Omen Technology products.  Any programs which use
  22.  * part or all of this software must be provided in source form
  23.  * with this notice intact except by written permission from Omen
  24.  * Technology Incorporated.
  25.  * 
  26.  * Use of this software for commercial or administrative purposes
  27.  * except when exclusively limited to interfacing Omen Technology
  28.  * products requires a per port license payment of $20.00 US per
  29.  * port (less in quantity).  Use of this code by inclusion,
  30.  * decompilation, reverse engineering or any other means
  31.  * constitutes agreement to these conditions and acceptance of
  32.  * liability to license the materials and payment of reasonable
  33.  * legal costs necessary to enforce this license agreement.
  34.  *
  35.  *
  36.  *        Omen Technology Inc        FAX: 503-621-3745
  37.  *        Post Office Box 4681
  38.  *        Portland OR 97208
  39.  *
  40.  *    This code is made available in the hope it will be useful,
  41.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  42.  *    DAMAGES OF ANY KIND.
  43.  *
  44.  *
  45.  *
  46.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  47.  * "COMMAND filename"  (Unix only)
  48.  *
  49.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  50.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  51.  *  character reads for these systems. Added 7-01-84 CAF
  52.  *
  53.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  54.  *
  55.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  56.  *  doesn't work properly (even though it compiles without error!),
  57.  *
  58.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  59.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  60.  *
  61.  *  -DMD may be added to compiler command line to compile in
  62.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  63.  *
  64.  *  HOWMANY may be tuned for best performance
  65.  *
  66.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  67.  */
  68.  
  69.  
  70.  
  71. #define LOGFILE "/tmp/rzlog"
  72. #include <stdio.h>
  73. #include <signal.h>
  74. #include <setjmp.h>
  75. #include <ctype.h>
  76. #include <errno.h>
  77. extern int errno;
  78. FILE *popen();
  79.  
  80. #define OK 0
  81. #define FALSE 0
  82. #define TRUE 1
  83. #define ERROR (-1)
  84.  
  85. /*
  86.  * Max value for HOWMANY is 255.
  87.  *   A larger value reduces system overhead but may evoke kernel bugs.
  88.  *   133 corresponds to an XMODEM/CRC sector
  89.  */
  90. #ifndef HOWMANY
  91. #define HOWMANY 133
  92. #endif
  93.  
  94. /* Ward Christensen / CP/M parameters - Don't change these! */
  95. #define ENQ 005
  96. #define CAN ('X'&037)
  97. #define XOFF ('s'&037)
  98. #define XON ('q'&037)
  99. #define SOH 1
  100. #define STX 2
  101. #define EOT 4
  102. #define ACK 6
  103. #define NAK 025
  104. #define CPMEOF 032
  105. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  106. #define TIMEOUT (-2)
  107. #define RCDO (-3)
  108. #define GCOUNT (-4)
  109. #define ERRORMAX 5
  110. #define RETRYMAX 5
  111. #define WCEOT (-10)
  112. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  113. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  114.  
  115. int Zmodem=0;        /* ZMODEM protocol requested */
  116. int Nozmodem = 0;    /* If invoked as "rb" */
  117. unsigned Baudrate = 2400;
  118. unsigned Effbaud = 2400;
  119. #include "rbsb.c"    /* most of the system dependent stuff here */
  120. #include "crctab.c"
  121. char endmsg[90] = {0};    /* Possible message to display on exit */
  122.  
  123. char *substr();
  124. FILE *fout;
  125.  
  126. /*
  127.  * Routine to calculate the free bytes on the current file system
  128.  *  ~0 means many free bytes (unknown)
  129.  */
  130. long getfree()
  131. {
  132.     return(~0L);    /* many free bytes ... */
  133. }
  134.  
  135. int Lastrx;
  136. long rxbytes;
  137. int Crcflg;
  138. int Firstsec;
  139. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  140. int errors;
  141. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  142. #ifdef ONEREAD
  143. /* Sorry, Regulus and some others don't work right in raw mode! */
  144. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  145. #else
  146. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  147. #endif
  148.  
  149. #define DEFBYTL 2000000000L    /* default rx file size */
  150. long Bytesleft;        /* number of bytes of incoming file left */
  151. long Modtime;        /* Unix style mod time for incoming file */
  152. int Filemode;        /* Unix style mode for incoming file */
  153. long Totalleft;
  154. long Filesleft;
  155. char Pathname[PATHLEN];
  156. char *Progname;        /* the name by which we were called */
  157.  
  158. int Batch=0;
  159. int Topipe=0;
  160. int Verbose=0;
  161. int Thisbinary;        /* current file is to be received in bin mode */
  162. int Blklen;        /* record length of received packets */
  163.  
  164. #ifdef SEGMENTS
  165. int chinseg = 0;    /* Number of characters received in this data seg */
  166. char secbuf[1+(SEGMENTS+1)*1024];
  167. #else
  168. char secbuf[1025];
  169. #endif
  170.  
  171.  
  172. char linbuf[HOWMANY];
  173. int Lleft=0;        /* number of characters in linbuf */
  174. time_t timep[2];
  175. char zconv;        /* ZMODEM file conversion request */
  176. char zmanag;        /* ZMODEM file management request */
  177. char ztrans;        /* ZMODEM file transport request */
  178. int Zctlesc;        /* Encode control characters */
  179. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  180.  
  181. jmp_buf tohere;        /* For the interrupt on RX timeout */
  182.  
  183. #define xsendline(c) sendline(c)
  184.  
  185. #include "zm.c"
  186.  
  187. #include "zmr.c"
  188.  
  189. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  190.  
  191. alrm()
  192. {
  193.     longjmp(tohere, -1);
  194. }
  195.  
  196. /* called by signal interrupt or terminate to clean things up */
  197. bibi(n)
  198. {
  199.     if (Zmodem)
  200.         zmputs(Attn);
  201.     canit(); mode(0);
  202.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  203.     cucheck();
  204.     exit(128+n);
  205. }
  206.  
  207. main(argc, argv)
  208. char *argv[];
  209. {
  210.     register char *cp;
  211.     register npats;
  212.     char *virgin, **patts;
  213.     char *getenv();
  214.     int exitcode = 0;
  215.  
  216.     Rxtimeout = 100;
  217.     setbuf(stderr, NULL);
  218.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  219.         Restricted=TRUE;
  220.  
  221.     from_cu();
  222.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  223.     npats = 0;
  224.     while (--argc) {
  225.         cp = *++argv;
  226.         if (*cp == '-') {
  227.             while( *++cp) {
  228.                 switch(*cp) {
  229.                 case '\\':
  230.                      cp[1] = toupper(cp[1]);  continue;
  231.                 case 'c':
  232.                     Crcflg=TRUE; break;
  233.                 case 'e':
  234.                     Zctlesc = 1; break;
  235.                 case 't':
  236.                     if (--argc < 1) {
  237.                         usage();
  238.                     }
  239.                     Rxtimeout = atoi(*++argv);
  240.                     if (Rxtimeout<10 || Rxtimeout>1000)
  241.                         usage();
  242.                     break;
  243.                 case 'w':
  244.                     if (--argc < 1) {
  245.                         usage();
  246.                     }
  247.                     Zrwindow = atoi(*++argv);
  248.                     break;
  249.                 case 'v':
  250.                     ++Verbose; break;
  251.                 default:
  252.                     usage();
  253.                 }
  254.             }
  255.         }
  256.         else if ( !npats && argc>0) {
  257.             if (argv[0][0]) {
  258.                 npats=argc;
  259.                 patts=argv;
  260.             }
  261.         }
  262.     }
  263.     if (npats > 1)
  264.         usage();
  265.     if (Batch && npats)
  266.         usage();
  267.     if (Verbose) {
  268.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  269.             printf("Can't open log file %s\n",LOGFILE);
  270.             exit(0200);
  271.         }
  272.         setbuf(stderr, NULL);
  273.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  274.     }
  275.     if (Fromcu) {
  276.         if (Verbose == 0)
  277.             Verbose = 2;
  278.     }
  279.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  280.     mode(1);
  281.     if (signal(SIGINT, bibi) == SIG_IGN) {
  282.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  283.     }
  284.     else {
  285.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  286.     }
  287.     signal(SIGTERM, bibi);
  288.     if (wcreceive(npats, patts)==ERROR) {
  289.         exitcode=0200;
  290.         canit();
  291.     }
  292.     mode(0);
  293.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  294.         canit();
  295.     if (exitcode)
  296.         cucheck();
  297.     if (endmsg[0])
  298.         printf("  %s: %s\r\n", Progname, endmsg);
  299.     printf("%s %s finished.\r\n", Progname, VERSION);
  300.     fflush(stdout);
  301.     exit(exitcode ? exitcode:0);
  302. }
  303.  
  304.  
  305. usage()
  306. {
  307.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  308.       Progname, VERSION, OS);
  309.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n\n");
  310.     fprintf(stderr,"Usage:    rz [-ev]        (ZMODEM)\n");
  311.     fprintf(stderr,"or    rb [-v]            (YMODEM)\n");
  312.     fprintf(stderr,"or    rx [-cv] file    (XMODEM or XMODEM-1k)\n\n");
  313.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  314.     fprintf(stderr,"      -e Escape control characters    (ZMODEM)\n");
  315.     fprintf(stderr,"      -v Verbose more v's give more info\n\n");
  316.     fprintf(stderr,
  317. "Supports incoming ZMODEM binary (-b), ASCII CR/LF>NL (-a), newer(-n),\n\
  318. newer+longer(-N), protect (-p), Crash Recovery (-r),\n\
  319. clobber (-y), match+clobber (-Y), compression (-Z), and append (-+).\n");
  320.     cucheck();
  321.     exit(1);
  322. }
  323. /*
  324.  *  Debugging information output interface routine
  325.  */
  326. /* VARARGS1 */
  327. vfile(f, a, b, c, d)
  328. char *f;
  329. long a, b, c, d;
  330. {
  331.     if (Verbose > 2) {
  332.         fprintf(stderr, f, a, b, c, d);
  333.         fprintf(stderr, "\n");
  334.     }
  335. }
  336.  
  337. /*
  338.  * Let's receive something already.
  339.  */
  340.  
  341. char *rbmsg =
  342. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
  343.  
  344. wcreceive(argc, argp)
  345. char **argp;
  346. {
  347.     register c;
  348.  
  349.     if (Batch || argc==0) {
  350.         Crcflg=1;
  351.         fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  352.         if (c=tryz()) {
  353.             if (c == ZCOMPL)
  354.                 return OK;
  355.             if (c == ERROR)
  356.                 goto fubar;
  357.             c = rzfiles();
  358.             if (c)
  359.                 goto fubar;
  360.         } else {
  361.             for (;;) {
  362.                 if (wcrxpn(secbuf)== ERROR)
  363.                     goto fubar;
  364.                 if (secbuf[0]==0)
  365.                     return OK;
  366.                 if (procheader(secbuf) == ERROR)
  367.                     goto fubar;
  368.                 if (wcrx()==ERROR)
  369.                     goto fubar;
  370.             }
  371.         }
  372.     } else {
  373.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  374.  
  375.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  376.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  377.         if ((fout=fopen(Pathname, "w")) == NULL)
  378.             return ERROR;
  379.         if (wcrx()==ERROR)
  380.             goto fubar;
  381.     }
  382.     return OK;
  383. fubar:
  384.     canit();
  385.     if (Topipe && fout) {
  386.         pclose(fout);  return ERROR;
  387.     }
  388.     Modtime = 1;
  389.     if (fout)
  390.         fclose(fout);
  391.     if (Restricted) {
  392.         unlink(Pathname);
  393.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  394.     }
  395.     return ERROR;
  396. }
  397.  
  398.  
  399. /*
  400.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  401.  * Length is indeterminate as long as less than Blklen
  402.  * A null string represents no more files (YMODEM)
  403.  */
  404. wcrxpn(rpn)
  405. char *rpn;    /* receive a pathname */
  406. {
  407.     register c;
  408.  
  409. #ifdef NFGVMIN
  410.     readline(1);
  411. #else
  412.     purgeline();
  413. #endif
  414.  
  415. et_tu:
  416.     Firstsec=TRUE;  Eofseen=FALSE;
  417.     sendline(Crcflg?WANTCRC:NAK);
  418.     Lleft=0;    /* Do read next time ... */
  419.     while ((c = wcgetsec(rpn, 100)) != 0) {
  420.         if (c == WCEOT) {
  421.             zperr( "Pathname fetch returned %d", c);
  422.             sendline(ACK);
  423.             Lleft=0;    /* Do read next time ... */
  424.             readline(1);
  425.             goto et_tu;
  426.         }
  427.         return ERROR;
  428.     }
  429.     sendline(ACK);
  430.     return OK;
  431. }
  432.  
  433. /*
  434.  * Adapted from CMODEM13.C, written by
  435.  * Jack M. Wierda and Roderick W. Hart
  436.  */
  437.  
  438. wcrx()
  439. {
  440.     register int sectnum, sectcurr;
  441.     register char sendchar;
  442.     register char *p;
  443.     int cblklen;            /* bytes to dump this block */
  444.  
  445.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  446.     sendchar=Crcflg?WANTCRC:NAK;
  447.  
  448.     for (;;) {
  449.         sendline(sendchar);    /* send it now, we're ready! */
  450.         Lleft=0;    /* Do read next time ... */
  451.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  452.         report(sectcurr);
  453.         if (sectcurr==(sectnum+1 &0377)) {
  454.             sectnum++;
  455.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  456.             if (putsec(secbuf, cblklen)==ERROR)
  457.                 return ERROR;
  458.             if ((Bytesleft-=cblklen) < 0)
  459.                 Bytesleft = 0;
  460.             sendchar=ACK;
  461.         }
  462.         else if (sectcurr==(sectnum&0377)) {
  463.             zperr( "Received dup Sector");
  464.             sendchar=ACK;
  465.         }
  466.         else if (sectcurr==WCEOT) {
  467.             if (closeit())
  468.                 return ERROR;
  469.             sendline(ACK);
  470.             Lleft=0;    /* Do read next time ... */
  471.             return OK;
  472.         }
  473.         else if (sectcurr==ERROR)
  474.             return ERROR;
  475.         else {
  476.             zperr( "Sync Error");
  477.             return ERROR;
  478.         }
  479.     }
  480. }
  481.  
  482. /*
  483.  * Wcgetsec fetches a Ward Christensen type sector.
  484.  * Returns sector number encountered or ERROR if valid sector not received,
  485.  * or CAN CAN received
  486.  * or WCEOT if eot sector
  487.  * time is timeout for first char, set to 4 seconds thereafter
  488.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  489.  *    (Caller must do that when he is good and ready to get next sector)
  490.  */
  491.  
  492. wcgetsec(rxbuf, maxtime)
  493. char *rxbuf;
  494. int maxtime;
  495. {
  496.     register checksum, wcj, firstch;
  497.     register unsigned short oldcrc;
  498.     register char *p;
  499.     int sectcurr;
  500.  
  501.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  502.  
  503.         if ((firstch=readline(maxtime))==STX) {
  504.             Blklen=1024; goto get2;
  505.         }
  506.         if (firstch==SOH) {
  507.             Blklen=128;
  508. get2:
  509.             sectcurr=readline(1);
  510.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  511.                 oldcrc=checksum=0;
  512.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  513.                     if ((firstch=readline(1)) < 0)
  514.                         goto bilge;
  515.                     oldcrc=updcrc(firstch, oldcrc);
  516.                     checksum += (*p++ = firstch);
  517.                 }
  518.                 if ((firstch=readline(1)) < 0)
  519.                     goto bilge;
  520.                 if (Crcflg) {
  521.                     oldcrc=updcrc(firstch, oldcrc);
  522.                     if ((firstch=readline(1)) < 0)
  523.                         goto bilge;
  524.                     oldcrc=updcrc(firstch, oldcrc);
  525.                     if (oldcrc & 0xFFFF)
  526.                         zperr( "CRC");
  527.                     else {
  528.                         Firstsec=FALSE;
  529.                         return sectcurr;
  530.                     }
  531.                 }
  532.                 else if (((checksum-firstch)&0377)==0) {
  533.                     Firstsec=FALSE;
  534.                     return sectcurr;
  535.                 }
  536.                 else
  537.                     zperr( "Checksum");
  538.             }
  539.             else
  540.                 zperr("Sector number garbled");
  541.         }
  542.         /* make sure eot really is eot and not just mixmash */
  543. #ifdef NFGVMIN
  544.         else if (firstch==EOT && readline(1)==TIMEOUT)
  545.             return WCEOT;
  546. #else
  547.         else if (firstch==EOT && Lleft==0)
  548.             return WCEOT;
  549. #endif
  550.         else if (firstch==CAN) {
  551.             if (Lastrx==CAN) {
  552.                 zperr( "Sender CANcelled");
  553.                 return ERROR;
  554.             } else {
  555.                 Lastrx=CAN;
  556.                 continue;
  557.             }
  558.         }
  559.         else if (firstch==TIMEOUT) {
  560.             if (Firstsec)
  561.                 goto humbug;
  562. bilge:
  563.             zperr( "TIMEOUT");
  564.         }
  565.         else
  566.             zperr( "Got 0%o sector header", firstch);
  567.  
  568. humbug:
  569.         Lastrx=0;
  570.         while(readline(1)!=TIMEOUT)
  571.             ;
  572.         if (Firstsec) {
  573.             sendline(Crcflg?WANTCRC:NAK);
  574.             Lleft=0;    /* Do read next time ... */
  575.         } else {
  576.             maxtime=40; sendline(NAK);
  577.             Lleft=0;    /* Do read next time ... */
  578.         }
  579.     }
  580.     /* try to stop the bubble machine. */
  581.     canit();
  582.     return ERROR;
  583. }
  584.  
  585. /*
  586.  * This version of readline is reasoably well suited for
  587.  * reading many characters.
  588.  *  (except, currently, for the Regulus version!)
  589.  *
  590.  * timeout is in tenths of seconds
  591.  */
  592. readline(timeout)
  593. int timeout;
  594. {
  595.     register n;
  596.     static char *cdq;    /* pointer for removing chars from linbuf */
  597.  
  598.     if (--Lleft >= 0) {
  599.         if (Verbose > 8) {
  600.             fprintf(stderr, "%02x ", *cdq&0377);
  601.         }
  602.         return (*cdq++ & 0377);
  603.     }
  604.     n = timeout/10;
  605.     if (n < 2)
  606.         n = 3;
  607.     if (Verbose > 5)
  608.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  609.           n, Readnum);
  610.     if (setjmp(tohere)) {
  611. #ifdef TIOCFLUSH
  612. /*        ioctl(0, TIOCFLUSH, 0); */
  613. #endif
  614.         Lleft = 0;
  615.         if (Verbose>1)
  616.             fprintf(stderr, "Readline:TIMEOUT\n");
  617.         return TIMEOUT;
  618.     }
  619.     signal(SIGALRM, alrm); alarm(n);
  620.     Lleft=read(0, cdq=linbuf, Readnum);
  621.     alarm(0);
  622.     if (Verbose > 5) {
  623.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  624.     }
  625.     if (Lleft < 1)
  626.         return TIMEOUT;
  627.     --Lleft;
  628.     if (Verbose > 8) {
  629.         fprintf(stderr, "%02x ", *cdq&0377);
  630.     }
  631.     return (*cdq++ & 0377);
  632. }
  633.  
  634.  
  635.  
  636. /*
  637.  * Purge the modem input queue of all characters
  638.  */
  639. purgeline()
  640. {
  641.     Lleft = 0;
  642. #ifdef USG
  643.     ioctl(0, TCFLSH, 0);
  644. #else
  645.     lseek(0, 0L, 2);
  646. #endif
  647. }
  648.  
  649.  
  650. /*
  651.  * Process incoming file information header
  652.  */
  653. procheader(name)
  654. char *name;
  655. {
  656.     register char *openmode, *p, **pp;
  657.     static dummy;
  658.     struct stat f;
  659.  
  660.     /* set default parameters and overrides */
  661.     openmode = "w";
  662.  
  663.     /*
  664.      *  Process ZMODEM remote file management requests
  665.      */
  666.     Thisbinary = (zconv != ZCNL);    /* Remote ASCII override */
  667.     if (zmanag == ZMAPND)
  668.         openmode = "a";
  669.  
  670.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  671.  
  672.     p = name + 1 + strlen(name);
  673.     if (*p) {    /* file coming from Unix or DOS system */
  674.         sscanf(p, "%ld%lo%o%lo%d%ld%d%d",
  675.           &Bytesleft, &Modtime, &Filemode,
  676.           &dummy, &Filesleft, &Totalleft, &dummy, &dummy);
  677.         if (Filemode & UNIXFILE)
  678.             ++Thisbinary;
  679.         if (Verbose) {
  680.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  681.               name, Bytesleft, Modtime, Filemode);
  682.             fprintf(stderr,  "YMODEM header: %s\n", p);
  683.         }
  684.     }
  685.  
  686.  
  687.     else {        /* File coming from CP/M system */
  688.         for (p=name; *p; ++p)        /* change / to _ */
  689.             if ( *p == '/')
  690.                 *p = '_';
  691.  
  692.         if ( *--p == '.')        /* zap trailing period */
  693.             *p = 0;
  694.     }
  695.  
  696.     strcpy(Pathname, name);
  697.     checkpath(name);
  698.  
  699.     if (*name && stat(name, &f)!= -1) {
  700.         zmanag &= ZMMASK;
  701.         vfile("Current %s is %ld %lo", name, f.st_size, f.st_mtime);
  702.         if (Thisbinary && zconv==ZCRESUM) {
  703.             rxbytes = f.st_size & ~511;
  704.             openit(name, "r+");
  705.             if ( !fout)
  706.                 return ZFERR;
  707.             if (Bytesleft < rxbytes)
  708.                 rxbytes = 0;
  709.             if (fseek(fout, rxbytes, 0)) {
  710.                 closeit();
  711.                 return ZFERR;
  712.             }
  713.             vfile("Crash recovery at %ld", rxbytes);
  714.             return 0;
  715.         }
  716.         else if ((zmanag==ZMNEW) ||
  717.           ((zmanag==ZMNEWL) && Bytesleft <= f.st_size) ) {
  718.             if ((f.st_mtime+1) >= Modtime)
  719.                 goto skipfile;
  720.             goto doopen;
  721.         }
  722.         else if (zmanag==ZMPROT)
  723.             goto skipfile;
  724.         else if ((zmanag&ZMMASK) != ZMCLOB)
  725.             goto skipfile;
  726.         goto doopen;
  727.     } else if (zmanag & ZMSKNOLOC) {
  728. skipfile:
  729.         vfile("Skipping %s", name);
  730.         return ZSKIP;
  731.     }
  732. doopen:
  733.     openit(name, openmode);
  734. #ifdef MD
  735.     if ( !fout)
  736.         if (make_dirs(name))
  737.             openit(name, openmode);
  738. #endif
  739.     if ( !fout)
  740.         return ZFERR;
  741.     return 0;
  742. }
  743.  
  744. openit(name, openmode)
  745. char *name, *openmode;
  746. {
  747.     fout = fopen(name, openmode);
  748. }
  749.  
  750. #ifdef MD
  751. /*
  752.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  753.  */
  754.  
  755. /*
  756.  * After a file/link/symlink/dir creation has failed, see if
  757.  * it's because some required directory was not present, and if
  758.  * so, create all required dirs.
  759.  */
  760. make_dirs(pathname)
  761. register char *pathname;
  762. {
  763.     register char *p;        /* Points into path */
  764.     int madeone = 0;        /* Did we do anything yet? */
  765.     int save_errno = errno;        /* Remember caller's errno */
  766.     char *strchr();
  767.  
  768.     if (errno != ENOENT)
  769.         return 0;        /* Not our problem */
  770.  
  771.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  772.         /* Avoid mkdir of empty string, if leading or double '/' */
  773.         if (p == pathname || p[-1] == '/')
  774.             continue;
  775.         /* Avoid mkdir where last part of path is '.' */
  776.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  777.             continue;
  778.         *p = 0;                /* Truncate the path there */
  779.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  780.             vfile("Made directory %s\n", pathname);
  781.             madeone++;        /* Remember if we made one */
  782.             *p = '/';
  783.             continue;
  784.         }
  785.         *p = '/';
  786.         if (errno == EEXIST)        /* Directory already exists */
  787.             continue;
  788.         /*
  789.          * Some other error in the mkdir.  We return to the caller.
  790.          */
  791.         break;
  792.     }
  793.     errno = save_errno;        /* Restore caller's errno */
  794.     return madeone;            /* Tell them to retry if we made one */
  795. }
  796.  
  797. #if (MD != 2)
  798. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  799. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  800. #define TERM_VALUE(status)    ((status) >> 8)
  801. /*
  802.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  803.  */
  804. mkdir(dpath, dmode)
  805. char *dpath;
  806. int dmode;
  807. {
  808.     int cpid, status;
  809.     struct stat statbuf;
  810.  
  811.     if (stat(dpath,&statbuf) == 0) {
  812.         errno = EEXIST;        /* Stat worked, so it already exists */
  813.         return -1;
  814.     }
  815.  
  816.     /* If stat fails for a reason other than non-existence, return error */
  817.     if (errno != ENOENT) return -1; 
  818.  
  819.     switch (cpid = fork()) {
  820.  
  821.     case -1:            /* Error in fork() */
  822.         return(-1);        /* Errno is set already */
  823.  
  824.     case 0:                /* Child process */
  825.         /*
  826.          * Cheap hack to set mode of new directory.  Since this
  827.          * child process is going away anyway, we zap its umask.
  828.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  829.          * directory.  Does anybody care?
  830.          */
  831.         status = umask(0);    /* Get current umask */
  832.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  833.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  834.         _exit(-1);        /* Can't exec /bin/mkdir */
  835.     
  836.     default:            /* Parent process */
  837.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  838.     }
  839.  
  840.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  841.         errno = EIO;        /* We don't know why, but */
  842.         return -1;        /* /bin/mkdir failed */
  843.     }
  844.  
  845.     return 0;
  846. }
  847. #endif /* MD != 2 */
  848. #endif /* MD */
  849.  
  850. /*
  851.  * Putsec writes the n characters of buf to receive file fout.
  852.  *  If not in binary mode, carriage returns, and all characters
  853.  *  starting with CPMEOF are discarded.
  854.  */
  855. putsec(buf, n)
  856. char *buf;
  857. register n;
  858. {
  859.     register char *p;
  860.  
  861.     if (n == 0)
  862.         return OK;
  863.     if (Thisbinary) {
  864.         for (p=buf; --n>=0; )
  865.             putc( *p++, fout);
  866.     }
  867.     else {
  868.         if (Eofseen)
  869.             return OK;
  870.         for (p=buf; --n>=0; ++p ) {
  871.             if ( *p == '\r')
  872.                 continue;
  873.             if (*p == CPMEOF) {
  874.                 Eofseen=TRUE; return OK;
  875.             }
  876.             putc(*p ,fout);
  877.         }
  878.     }
  879.     return OK;
  880. }
  881.  
  882. /*
  883.  *  Send a character to modem.  Small is beautiful.
  884.  */
  885. sendline(c)
  886. {
  887.     char d;
  888.  
  889.     d = c;
  890.     if (Verbose>6)
  891.         fprintf(stderr, "Sendline: %x\n", c);
  892.     write(1, &d, 1);
  893. }
  894.  
  895. flushmo() {}
  896. flushmoc() {}
  897.  
  898. /*
  899.  * substr(string, token) searches for token in string s
  900.  * returns pointer to token within string if found, NULL otherwise
  901.  */
  902. char *
  903. substr(s, t)
  904. register char *s,*t;
  905. {
  906.     register char *ss,*tt;
  907.     /* search for first char of token */
  908.     for (ss=s; *s; s++)
  909.         if (*s == *t)
  910.             /* compare token with substring */
  911.             for (ss=s,tt=t; ;) {
  912.                 if (*tt == 0)
  913.                     return s;
  914.                 if (*ss++ != *tt++)
  915.                     break;
  916.             }
  917.     return NULL;
  918. }
  919.  
  920. /*
  921.  * Log an error
  922.  */
  923. /*VARARGS1*/
  924. zperr(s,p,u)
  925. char *s, *p, *u;
  926. {
  927.     if (Verbose <= 0)
  928.         return;
  929.     fprintf(stderr, "Retry %d: ", errors);
  930.     fprintf(stderr, s, p, u);
  931.     fprintf(stderr, "\n");
  932. }
  933.  
  934. /* send cancel string to get the other end to shut up */
  935. canit()
  936. {
  937.     static char canistr[] = {
  938.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  939.     };
  940.  
  941.     printf(canistr);
  942.     Lleft=0;    /* Do read next time ... */
  943.     fflush(stdout);
  944. }
  945.  
  946.  
  947. report(sct)
  948. int sct;
  949. {
  950.     if (Verbose>1)
  951.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  952. }
  953.  
  954. /*
  955.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  956.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  957.  * If called as rb use YMODEM protocol
  958.  */
  959. chkinvok(s)
  960. char *s;
  961. {
  962.     register char *p;
  963.  
  964.     p = s;
  965.     while (*p == '-')
  966.         s = ++p;
  967.     while (*p)
  968.         if (*p++ == '/')
  969.             s = p;
  970.     if (*s == 'v') {
  971.         Verbose=1; ++s;
  972.     }
  973.     Progname = s;
  974.     if (s[0]=='r' && s[1]=='z')
  975.         Batch = TRUE;
  976.     if (s[0]=='r' && s[1]=='b')
  977.         Batch = Nozmodem = TRUE;
  978.     if (s[2] && s[0]=='r' && s[1]=='b')
  979.         Topipe = 1;
  980.     if (s[2] && s[0]=='r' && s[1]=='z')
  981.         Topipe = 1;
  982. }
  983.  
  984. /*
  985.  * Totalitarian Communist pathname processing
  986.  */
  987. checkpath(name)
  988. char *name;
  989. {
  990.     if (Restricted) {
  991.         if (fopen(name, "r") != NULL) {
  992.             canit();
  993.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  994.             bibi(-1);
  995.         }
  996.         /* restrict pathnames to current tree or uucppublic */
  997.         if ( substr(name, "../")
  998.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  999.             canit();
  1000.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  1001.             bibi(-1);
  1002.         }
  1003.     }
  1004. }
  1005.  
  1006. /*
  1007.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1008.  *  Handles ZSINIT frame
  1009.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1010.  *   ZCOMPL if transaction finished,  else 0
  1011.  */
  1012. tryz()
  1013. {
  1014.     register c, n;
  1015.     register cmdzack1flg;
  1016.  
  1017.     if (Nozmodem)        /* Check for "rb" program name */
  1018.         return 0;
  1019.  
  1020.  
  1021.     for (n=Zmodem?15:5; --n>=0; ) {
  1022.         /* Set buffer length (0) and capability flags */
  1023. #ifdef SEGMENTS
  1024.         stohdr(SEGMENTS*1024L);
  1025. #else
  1026.         stohdr(0L);
  1027. #endif
  1028. #ifdef CANBREAK
  1029.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1030. #else
  1031.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1032. #endif
  1033.         if (Zctlesc)
  1034.             Txhdr[ZF0] |= TESCCTL;
  1035.         Txhdr[ZF0] |= CANRLE;
  1036.         Txhdr[ZF1] = CANVHDR;
  1037.         /* tryzhdrtype may == ZRINIT */
  1038.         zshhdr(4,tryzhdrtype, Txhdr);
  1039.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1040.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1041. again:
  1042.         switch (zgethdr(Rxhdr, 0)) {
  1043.         case ZRQINIT:
  1044.             if (Rxhdr[ZF3] & 0x80)
  1045.                 Usevhdrs = 1;    /* we can var header */
  1046.             continue;
  1047.         case ZEOF:
  1048.             continue;
  1049.         case TIMEOUT:
  1050.             continue;
  1051.         case ZFILE:
  1052.             zconv = Rxhdr[ZF0];
  1053.             zmanag = Rxhdr[ZF1];
  1054.             ztrans = Rxhdr[ZF2];
  1055.             if (Rxhdr[ZF3] & ZCANVHDR)
  1056.                 Usevhdrs = TRUE;
  1057.             tryzhdrtype = ZRINIT;
  1058.             c = zrdata(secbuf, 1024);
  1059.             mode(3);
  1060.             if (c == GOTCRCW)
  1061.                 return ZFILE;
  1062.             zshhdr(4,ZNAK, Txhdr);
  1063.             goto again;
  1064.         case ZSINIT:
  1065.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1066.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  1067.                 stohdr(1L);
  1068.                 zshhdr(4,ZACK, Txhdr);
  1069.                 goto again;
  1070.             }
  1071.             zshhdr(4,ZNAK, Txhdr);
  1072.             goto again;
  1073.         case ZFREECNT:
  1074.             stohdr(getfree());
  1075.             zshhdr(4,ZACK, Txhdr);
  1076.             goto again;
  1077.         case ZCOMMAND:
  1078.             cmdzack1flg = Rxhdr[ZF0];
  1079.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1080.                 if (cmdzack1flg & ZCACK1)
  1081.                     stohdr(0L);
  1082.                 else
  1083.                     stohdr((long)sys2(secbuf));
  1084.                 purgeline();    /* dump impatient questions */
  1085.                 do {
  1086.                     zshhdr(4,ZCOMPL, Txhdr);
  1087.                 }
  1088.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1089.                 ackbibi();
  1090.                 if (cmdzack1flg & ZCACK1)
  1091.                     exec2(secbuf);
  1092.                 return ZCOMPL;
  1093.             }
  1094.             zshhdr(4,ZNAK, Txhdr); goto again;
  1095.         case ZCOMPL:
  1096.             goto again;
  1097.         default:
  1098.             continue;
  1099.         case ZFIN:
  1100.             ackbibi(); return ZCOMPL;
  1101.         case ZCAN:
  1102.             return ERROR;
  1103.         }
  1104.     }
  1105.     return 0;
  1106. }
  1107.  
  1108. /*
  1109.  * Receive 1 or more files with ZMODEM protocol
  1110.  */
  1111. rzfiles()
  1112. {
  1113.     register c;
  1114.  
  1115.     for (;;) {
  1116.         switch (c = rzfile()) {
  1117.         case ZEOF:
  1118.         case ZSKIP:
  1119.             switch (tryz()) {
  1120.             case ZCOMPL:
  1121.                 return OK;
  1122.             default:
  1123.                 return ERROR;
  1124.             case ZFILE:
  1125.                 break;
  1126.             }
  1127.             continue;
  1128.         default:
  1129.             return c;
  1130.         case ERROR:
  1131.             return ERROR;
  1132.         }
  1133.     }
  1134. }
  1135.  
  1136. /*
  1137.  * Receive a file with ZMODEM protocol
  1138.  *  Assumes file name frame is in secbuf
  1139.  */
  1140. rzfile()
  1141. {
  1142.     register c, n;
  1143.     long rxbytes;
  1144.  
  1145.     Eofseen=FALSE;
  1146.     if (c = procheader(secbuf)) {
  1147.         return (tryzhdrtype = c);
  1148.     }
  1149.  
  1150.     n = 20; rxbytes = 0l;
  1151.  
  1152.     for (;;) {
  1153. #ifdef SEGMENTS
  1154.         chinseg = 0;
  1155. #endif
  1156.         stohdr(rxbytes);
  1157.         zshhdr(4,ZRPOS, Txhdr);
  1158. nxthdr:
  1159.         switch (c = zgethdr(Rxhdr, 0)) {
  1160.         default:
  1161.             vfile("rzfile: Wrong header %d", c);
  1162.             if ( --n < 0) {
  1163.                 sprintf(endmsg, "rzfile: Wrong header %d", c);
  1164.                 return ERROR;
  1165.             }
  1166.             continue;
  1167.         case ZCAN:
  1168.             sprintf(endmsg, "Sender CANcelled");
  1169.             return ERROR;
  1170.         case ZNAK:
  1171. #ifdef SEGMENTS
  1172.             putsec(secbuf, chinseg);
  1173.             chinseg = 0;
  1174. #endif
  1175.             if ( --n < 0) {
  1176.                 sprintf(endmsg, "rzfile: got ZNAK", c);
  1177.                 return ERROR;
  1178.             }
  1179.             continue;
  1180.         case TIMEOUT:
  1181. #ifdef SEGMENTS
  1182.             putsec(secbuf, chinseg);
  1183.             chinseg = 0;
  1184. #endif
  1185.             if ( --n < 0) {
  1186.                 sprintf(endmsg, "rzfile: TIMEOUT", c);
  1187.                 return ERROR;
  1188.             }
  1189.             continue;
  1190.         case ZFILE:
  1191.             zrdata(secbuf, 1024);
  1192.             continue;
  1193.         case ZEOF:
  1194. #ifdef SEGMENTS
  1195.             putsec(secbuf, chinseg);
  1196.             chinseg = 0;
  1197. #endif
  1198.             if (rclhdr(Rxhdr) != rxbytes) {
  1199.                 /*
  1200.                  * Ignore eof if it's at wrong place - force
  1201.                  *  a timeout because the eof might have gone
  1202.                  *  out before we sent our zrpos.
  1203.                  */
  1204.                 errors = 0;  goto nxthdr;
  1205.             }
  1206.             if (closeit()) {
  1207.                 tryzhdrtype = ZFERR;
  1208.                 vfile("rzfile: closeit returned <> 0");
  1209.                 sprintf(endmsg,"Error closing file");
  1210.                 return ERROR;
  1211.             }
  1212.             vfile("rzfile: normal EOF");
  1213.             return c;
  1214.         case ERROR:    /* Too much garbage in header search error */
  1215. #ifdef SEGMENTS
  1216.             putsec(secbuf, chinseg);
  1217.             chinseg = 0;
  1218. #endif
  1219.             if ( --n < 0) {
  1220.                 sprintf(endmsg, "Persistent CRC or other ERROR");
  1221.                 return ERROR;
  1222.             }
  1223.             zmputs(Attn);
  1224.             continue;
  1225.         case ZSKIP:
  1226. #ifdef SEGMENTS
  1227.             putsec(secbuf, chinseg);
  1228.             chinseg = 0;
  1229. #endif
  1230.             Modtime = 1;
  1231.             closeit();
  1232.             sprintf(endmsg, "Sender SKIPPED file");
  1233.             return c;
  1234.         case ZDATA:
  1235.             if (rclhdr(Rxhdr) != rxbytes) {
  1236.                 if ( --n < 0) {
  1237.                     sprintf(endmsg,"Data has bad addr");
  1238.                     return ERROR;
  1239.                 }
  1240. #ifdef SEGMENTS
  1241.                 putsec(secbuf, chinseg);
  1242.                 chinseg = 0;
  1243. #endif
  1244.                 zmputs(Attn);  continue;
  1245.             }
  1246. moredata:
  1247.             if (Verbose>1)
  1248.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1249.                   rxbytes, Crc32r?" CRC-32":"");
  1250. #ifdef SEGMENTS
  1251.             if (chinseg >= (1024 * SEGMENTS)) {
  1252.                 putsec(secbuf, chinseg);
  1253.                 chinseg = 0;
  1254.             }
  1255.             switch (c = zrdata(secbuf+chinseg, 1024))
  1256. #else
  1257.             switch (c = zrdata(secbuf, 1024))
  1258. #endif
  1259.             {
  1260.             case ZCAN:
  1261. #ifdef SEGMENTS
  1262.                 putsec(secbuf, chinseg);
  1263.                 chinseg = 0;
  1264. #endif
  1265.                 sprintf(endmsg, "Sender CANcelled");
  1266.                 return ERROR;
  1267.             case ERROR:    /* CRC error */
  1268. #ifdef SEGMENTS
  1269.                 putsec(secbuf, chinseg);
  1270.                 chinseg = 0;
  1271. #endif
  1272.                 if ( --n < 0) {
  1273.                     sprintf(endmsg, "Persistent CRC or other ERROR");
  1274.                     return ERROR;
  1275.                 }
  1276.                 zmputs(Attn);
  1277.                 continue;
  1278.             case TIMEOUT:
  1279. #ifdef SEGMENTS
  1280.                 putsec(secbuf, chinseg);
  1281.                 chinseg = 0;
  1282. #endif
  1283.                 if ( --n < 0) {
  1284.                     sprintf(endmsg, "TIMEOUT");
  1285.                     return ERROR;
  1286.                 }
  1287.                 continue;
  1288.             case GOTCRCW:
  1289.                 n = 20;
  1290. #ifdef SEGMENTS
  1291.                 chinseg += Rxcount;
  1292.                 putsec(secbuf, chinseg);
  1293.                 chinseg = 0;
  1294. #else
  1295.                 putsec(secbuf, Rxcount);
  1296. #endif
  1297.                 rxbytes += Rxcount;
  1298.                 stohdr(rxbytes);
  1299.                 zshhdr(4,ZACK, Txhdr);
  1300.                 sendline(XON);
  1301.                 goto nxthdr;
  1302.             case GOTCRCQ:
  1303.                 n = 20;
  1304. #ifdef SEGMENTS
  1305.                 chinseg += Rxcount;
  1306. #else
  1307.                 putsec(secbuf, Rxcount);
  1308. #endif
  1309.                 rxbytes += Rxcount;
  1310.                 stohdr(rxbytes);
  1311.                 zshhdr(4,ZACK, Txhdr);
  1312.                 goto moredata;
  1313.             case GOTCRCG:
  1314.                 n = 20;
  1315. #ifdef SEGMENTS
  1316.                 chinseg += Rxcount;
  1317. #else
  1318.                 putsec(secbuf, Rxcount);
  1319. #endif
  1320.                 rxbytes += Rxcount;
  1321.                 goto moredata;
  1322.             case GOTCRCE:
  1323.                 n = 20;
  1324. #ifdef SEGMENTS
  1325.                 chinseg += Rxcount;
  1326. #else
  1327.                 putsec(secbuf, Rxcount);
  1328. #endif
  1329.                 rxbytes += Rxcount;
  1330.                 goto nxthdr;
  1331.             }
  1332.         }
  1333.     }
  1334. }
  1335.  
  1336. /*
  1337.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1338.  *   and \335 (break signal)
  1339.  */
  1340. zmputs(s)
  1341. char *s;
  1342. {
  1343.     register c;
  1344.  
  1345.     while (*s) {
  1346.         switch (c = *s++) {
  1347.         case '\336':
  1348.             sleep(1); continue;
  1349.         case '\335':
  1350.             sendbrk(); continue;
  1351.         default:
  1352.             sendline(c);
  1353.         }
  1354.     }
  1355. }
  1356.  
  1357. /*
  1358.  * Close the receive dataset, return OK or ERROR
  1359.  */
  1360. closeit()
  1361. {
  1362.     time_t time();
  1363.  
  1364.     if (Topipe) {
  1365.         if (pclose(fout)) {
  1366.             return ERROR;
  1367.         }
  1368.         return OK;
  1369.     }
  1370.     if (fclose(fout)==ERROR) {
  1371.         fprintf(stderr, "file close ERROR\n");
  1372.         return ERROR;
  1373.     }
  1374.     if (Modtime) {
  1375.         timep[0] = time(NULL);
  1376.         timep[1] = Modtime;
  1377.         utime(Pathname, timep);
  1378.     }
  1379.     if ((Filemode&S_IFMT) == S_IFREG)
  1380.         chmod(Pathname, (07777 & Filemode));
  1381.     return OK;
  1382. }
  1383.  
  1384. /*
  1385.  * Ack a ZFIN packet, let byegones be byegones
  1386.  */
  1387. ackbibi()
  1388. {
  1389.     register n;
  1390.  
  1391.     vfile("ackbibi:");
  1392.     Readnum = 1;
  1393.     stohdr(0L);
  1394.     for (n=3; --n>=0; ) {
  1395.         purgeline();
  1396.         zshhdr(4,ZFIN, Txhdr);
  1397.         switch (readline(100)) {
  1398.         case 'O':
  1399.             readline(1);    /* Discard 2nd 'O' */
  1400.             vfile("ackbibi complete");
  1401.             return;
  1402.         case RCDO:
  1403.             return;
  1404.         case TIMEOUT:
  1405.         default:
  1406.             break;
  1407.         }
  1408.     }
  1409. }
  1410.  
  1411.  
  1412.  
  1413. /*
  1414.  * Local console output simulation
  1415.  */
  1416. bttyout(c)
  1417. {
  1418.     if (Verbose || Fromcu)
  1419.         putc(c, stderr);
  1420. }
  1421.  
  1422. /*
  1423.  * Strip leading ! if present, do shell escape. 
  1424.  */
  1425. sys2(s)
  1426. register char *s;
  1427. {
  1428.     if (*s == '!')
  1429.         ++s;
  1430.     return system(s);
  1431. }
  1432. /*
  1433.  * Strip leading ! if present, do exec.
  1434.  */
  1435. exec2(s)
  1436. register char *s;
  1437. {
  1438.     if (*s == '!')
  1439.         ++s;
  1440.     mode(0);
  1441.     execl("/bin/sh", "sh", "-c", s);
  1442. }
  1443. /* End of rz.c */
  1444.